﻿﻿/* **********************************************************************************
 * Copyright (c) 2011 John Hughes
 *
 * j9Script is licenced under the Microsoft Reciprocal License (Ms-RL).
 *
 * Project Website: http://j9Script.codeplex.com/
 * **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace J9Script.Internal
{
    internal enum TokenTypeEnum
    {
        Identifier,  // variable name, function, keyword
        Operator, // +, -
        NumberLiteral,   // 123.45
        RegularStringLiteral,   // "hello"
        VerbatimStringLiteral,  // @"c:\dir\test.txt"
        BooleanLiteral,  // true, false
        NullLiteral,     // null
        Keyword,  // "new", "if", "else", "while", ...

        EvaluatedExpression,  // This just means that it is the result of evaluating an expression, like "1 + 2", or "mystring.Length" or "VAL("10")".
        Empty,     // nothing in here
        EndOfStatement, // ";"
        EndOfScript
    }
	
	[Serializable]
    internal struct Token
    {
        public string IdentifierName;  // Only assigned when the type is an Identifier.
        private IScriptObject _scriptObj;
        public TokenTypeEnum TokenType;
        public ScriptPosition Position;
        public string TokenString;
        public IScriptArray ParentArrayObject;  // Only assigned when the type is an Array
        public int ParentArrayIndex;  // Only assigned when the type is an Array
        public bool IsUndefinedIdentifier; // indicates if this token is for an undefined identifier or a class name

        public Token(IScriptObject value, TokenTypeEnum tokentype)
            : this(null, value, tokentype, ScriptPosition.Empty)
        {
        }
        public Token(IScriptObject value, TokenTypeEnum tokentype, ScriptPosition position, string sourceString)
            : this(null, value, tokentype, position, sourceString)
        {
        }
        public Token(string identifierName, IScriptObject value, TokenTypeEnum tokentype)
            : this(identifierName, value, tokentype, ScriptPosition.Empty)
        {
        }
        public Token(string identifierName, IScriptObject value, TokenTypeEnum tokentype, ScriptPosition position)
            : this(identifierName, value, tokentype, ScriptPosition.Empty, null)
        {
        }
        public Token(string identifierName, IScriptObject value, TokenTypeEnum tokentype, ScriptPosition position, string sourceString)
        {
            IdentifierName = identifierName;
            _scriptObj = value;
            TokenType = tokentype;
            Position = position;
            TokenString = sourceString;
            ParentArrayObject = null;
            ParentArrayIndex = -1;
            IsUndefinedIdentifier = false;
        }

        public Token(IScriptArray array, int arrayIndex, IScriptObject arrayItemValue, TokenTypeEnum tokentype)
        {
            IdentifierName = null;
            _scriptObj = arrayItemValue;
            TokenType = tokentype;
            Position = ScriptPosition.Empty;
            TokenString = null;
            ParentArrayObject = array;
            ParentArrayIndex = arrayIndex;
            IsUndefinedIdentifier = false;
        }

        public IScriptObject ScriptObj
        {
            get { return _scriptObj; }
            set
            {
                _scriptObj = value;

                // When the script object property is set, clear the is undefined identifier flag.
                IsUndefinedIdentifier = false;
            }
        }

        /// <summary>
        /// Indicates if the token's script object is a NullLiteral. Since 
        /// </summary>
        public bool IsNull
        {
            get { return _scriptObj == null && IsUndefinedIdentifier == false; }
        }
        
        public override string ToString()
        {
            return TokenType.ToString() + ", \"" + TokenString + "\"";
        }
        public bool IsEmpty
        {
            get { return TokenType == TokenTypeEnum.Empty; }
        }
        public static Token Empty
        {
            get
            {
                return new Token(null, TokenTypeEnum.Empty);
            }
        }
        public bool IsEndOfScript
        {
            get { return TokenType == TokenTypeEnum.EndOfScript; }
        }
        public static Token EndOfScript
        {
            get
            {
                return new Token(null, TokenTypeEnum.EndOfScript);
            }
        }
        public bool IsEndOfStatement
        {
            get { return TokenType == TokenTypeEnum.EndOfStatement; }
        }
        public static Token EndOfStatement
        {
            get
            {
                return new Token(null, TokenTypeEnum.EndOfStatement);
            }
        }
        public bool IsArrayElement
        {
            get
            {
                return ParentArrayObject != null;
            }
        }


        //public bool IsUndefinedIdentifier
        //{
        //    get
        //    {
        //        return TokenType == TokenTypeEnum.Identifier && ScriptObj == null;
        //    }
        //}

    }

}
